home *** CD-ROM | disk | FTP | other *** search
- /*============================================================
- ShowStackChain.c
-
- greggor@apple.com
-
- This package records and displays the current stack
- chain walking the A6 links. It does not grok every
- possible format of MacsBug symbol names, only the ones
- generated by Think C.
-
- Some modification will be required to get this to
- work with MPW. (Move 'GetA6' and 'GetSP' into a .a file)
- ============================================================*/
- #include <Types.h>
- #include <Memory.h>
- #include <Resources.h>
- #include <setjmp.h>
-
- #include "ShowStackChain.h"
-
- #ifndef __FAILUREHANDLER__
- #include "FailureHandler.h"
- #endif
- #ifndef __MODALSCROLLTEXT__
- #include "ModalScrollText.h"
- #endif
- #ifndef __STRINGUTILITIES__
- #include "StringUtilities.h"
- #endif
-
- #ifndef __SYSEQU__
- #include "SysEqu.h"
- #endif
-
- /*
- // Prototypes for routines used privately
- */
- void PrivateAsmRoutines(void);
- void* GetA6(void);
- void* GetSP(void);
- short GetMacsBugSymName( short* returnAddress, char* where, short maxChars );
-
- /*
- // Global to stash stack chain durring failure handling
- */
- StackChainInfo gFailureStackChain;
-
- /*-------------------------------------------------------------------
- Routines that get the value of A6 and A7:
- -------------------------------------------------------------------*/
- void PrivateAsmRoutines()
- {
- asm
- {
- extern GetA6:
-
- move.l A6,D0
- rts
-
- extern GetSP:
-
- move.l A7,D0
- rts
- }
- }
-
- /*-------------------------------------------------------------------
- This function is called during exception handling to
- record the state of the stack frame before it is destroyed
- by longjmp
- -------------------------------------------------------------------*/
- void RecordStackChain( StackChainInfo* stackChainInfo )
- {
- long* theReturnAddress;
- long* a6Chain;
- long* stackTop;
- short segNum;
-
- stackChainInfo->fEntries = 0;
- /*
- // Walk the stack & record every return address
- // we can find.
- */
- a6Chain = (long*)GetA6();
- stackTop = (long*)GetSP();
- while( (stackChainInfo->fEntries < kMaxStackChainEntries) && (StripAddress(a6Chain) >= StripAddress(stackTop) ) && (StripAddress(a6Chain) <= StripAddress( (void*)(*((long*)CurStackBase))) ) )
- {
- theReturnAddress = (long*) *(a6Chain + 1);
- stackChainInfo->fReturnAddress[stackChainInfo->fEntries++] = theReturnAddress;
-
- a6Chain = (long*)*a6Chain;
- }
- }
-
- /*-------------------------------------------------------------------
- Copy the MacsBug symbol name associated with the routine
- found at 'returnAddress' into the character string at 'where'
- -------------------------------------------------------------------*/
- short GetMacsBugSymName( short* returnAddress, char* where, short maxChars )
- {
- short* search;
- short maxSearch;
- short offset;
- short count = 0;
-
- /*
- // We always want to leave at least three characters
- // for the offset into the routine
- */
- maxChars -= 7;
- if( maxChars <= 0 )
- return;
- /*
- // First look for the symbol name
- */
- maxSearch = 0x3FFF;
- search = returnAddress;
- while( maxSearch-- )
- {
- long* compare = (long*)search;
-
- if( *compare == 0x4E5E4E75 )
- {
- unsigned char* symName = (unsigned char*)compare;
- short symLength;
-
- symName += 4;
-
- /*
- // Determine if the symbol name is
- // 8 characters long, 16 characters long,
- // or *symName characters long
- */
- if( (*symName & 0x7F) < 0x20 )
- {
- symLength = *symName & 0x7F;
- ++symName;
- }
- else if( *symName >= 0x80 )
- {
- symLength = 16;
- }
- else
- {
- symLength = 8;
- }
-
- /*
- // Copy the symbol name into the string
- */
- while( ( (symLength--) > 0 ) && (*symName) && (count < maxChars) )
- {
- where[count++] = *symName++;
- }
-
- break;
- }
- ++search;
- }
-
- /*
- // If there's no symbol name, don't search for an offset
- */
- if( !count )
- return count;
-
- /*
- // Now look for the 'LNK' instruction
- */
- maxSearch = 0x3FFF;
- search = returnAddress;
- offset = 0;
- while( maxSearch-- )
- {
- if( *search == 0x4E56 )
- {
- where[count++] = ' ';
- where[count++] = '+';
- where[count++] = ' ';
-
- AddHexShortToString( &where[count], offset );
- count += 4;
-
- break;
- }
- --search;
- offset += 2;
- }
-
- return count;
- }
-
- /*----------------------------------------------------------------------
- Show the specified stack chain
- ----------------------------------------------------------------------*/
- void ShowStackChain( Str255 title, StackChainInfo* stackChainInfo )
- {
- char* stackText;
- Size textBufSize;
- #define kMaxLineLen 40
-
- textBufSize = (stackChainInfo->fEntries * kMaxLineLen) + 4;
- stackText = (char*)NewPtr( textBufSize );
- if( stackText != nil )
- {
- Size textLen = 0;
- short i;
-
- for( i=0; i<stackChainInfo->fEntries; ++i )
- {
- short* returnAddress = stackChainInfo->fReturnAddress[i];
-
- /*
- // Insert the return address and a space into the string
- */
- AddHexLongToString( &stackText[textLen], (long)returnAddress );
- textLen += 8;
- stackText[textLen++] = ' ';
- /*
- // Insert the macsbug name
- */
- textLen += GetMacsBugSymName( returnAddress, &stackText[textLen], kMaxLineLen - 10 );
- /*
- // Add a CR at the end of the line
- */
- stackText[textLen++] = '\r';
- }
- /*
- // Add on a terminator just for fun (it's not required)
- */
- stackText[textLen++] = 0;
-
- /*
- // We should be cooler than this
- */
- if( textLen > textBufSize )
- DebugStr( "\pTable overflow!" );
-
- ModalScrollText( title, stackText, textLen );
- }
- }
-
- /*----------------------------------------------------------------------
- Record the stack chain at time of failure (called by failure
- handler)
- ----------------------------------------------------------------------*/
- void RecordFailureStackChain(void)
- {
- RecordStackChain(&gFailureStackChain);
- }
-
- /*----------------------------------------------------------------------
- Show the stack chain that was recorded at the last failure
- ----------------------------------------------------------------------*/
- void ShowFailureStackChain(Str255 title)
- {
- ShowStackChain(title, &gFailureStackChain);
- }
-
- /*----------------------------------------------------------------------
- Install 'RecordFailureStackChain' in the failure handler
- ----------------------------------------------------------------------*/
- void InitShowStackChain()
- {
- gFailureStackChain.fEntries = 0;
- SetExceptionNotifyProc((NotifyFailureProc)RecordFailureStackChain);
- }
-
-
-
-